package assembler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JOptionPane;


public class PassOne {

	public static int startingLocation = 0;
	public static int locationCounter = 0;
	public static int lineNumber = 1;
	public static ListFile listFile;
	private static int opCode;
	private static int programLength = 0;
	private static String DUPLICATE_SYMBOL_ERROR = "Duplicate symbol";
	private static String INVALID_OPERATION_ERROR = "Invalid Operation";
	public static Map<String, Integer> symbolTable = new HashMap<String, Integer>();
	private static boolean formatFour;
	private static String originalMnemonic;

	public static void readLine(int index) throws Exception{
		String[] line = Assembler.sourceFile[index];
		String mnemonic;
		listFile = new ListFile();
		if(line.length > 2 && line[1].equals("START")){
			locationCounter = Integer.parseInt(line[2], 16);
			startingLocation = locationCounter;
			listFile.setIntermediateLineValue(lineNumber, locationCounter, line[0], line[1], line[2]);
			lineNumber += 1;
			Assembler.bufferedWriter.write(listFile.outputLine(0));
			Assembler.bufferedWriter.newLine();
			return;
		}
		formatFour = false;
		if(line.length == 3){
			String label = line[0];
			if(!symbolTable.containsKey(label)){
				putLabelInSymbolTable(label);
				listFile.label = label;
			}
			else showErrorMessage(lineNumber, DUPLICATE_SYMBOL_ERROR);
		}
		if (".".equalsIgnoreCase(line[0])){
			mnemonic = line[0];
			listFile.operand = "";
			if(line.length > 1){
				for (int i = 1; i < line.length; i++){
					listFile.operand += line[i] + " ";
				}	
			}
			listFile.setIntermediateLineValue(lineNumber, mnemonic, listFile.operand);
			Assembler.bufferedWriter.write(listFile.outputCommentLine(index));
			Assembler.bufferedWriter.newLine();
			lineNumber += 1;
			return;
		}
		if ("BASE".equalsIgnoreCase(line[0])){
			mnemonic = line[0];
			listFile.operand = line[1];
			listFile.setIntermediateLineValue(lineNumber, mnemonic, listFile.operand);
			Assembler.bufferedWriter.write(listFile.outputBaseLine(index));
			Assembler.bufferedWriter.newLine();
			lineNumber += 1;
			return;
		}
		originalMnemonic = "";
		switch(line.length){
		case 1:	
			mnemonic = testIfMnemonicIsFormatFour(line[0]);
			listFile.operand = "";
			break;
		default:
			mnemonic = testIfMnemonicIsFormatFour(line[line.length - 2]);
			listFile.operand = line[line.length - 1];
			break;
		}
		opCode = OpCodeMap.getOpCode(mnemonic);
		listFile.setIntermediateLineValue(lineNumber, locationCounter, opCode, originalMnemonic);
		switch(opCode){	
		case OpCodeMap.notFound:
			showErrorMessage(lineNumber, INVALID_OPERATION_ERROR);
			break;		
		case OpCodeMap.WORD:						
			locationCounter += 3;
			break;
		case OpCodeMap.RESW:
			locationCounter += 3 * Integer.parseInt(line[line.length - 1]);
			break;
		case OpCodeMap.RESB:
			locationCounter += Integer.parseInt(line[line.length - 1]);
			break;
		case OpCodeMap.BYTE:
			String [] sta = line[line.length - 1].split("'");		
			if(sta[0].equals("C"))
				locationCounter += sta[1].length();
			else if(sta[0].equals("X"))
				locationCounter += (int)(sta[1].length() * 0.5 + 0.5);
			break;
		default:
			if (OpCodeMap.isOpCodeInFormatTable(mnemonic)) {
				locationCounter += 2;
			} else if (formatFour) {
				locationCounter += 4;
			} else {
				locationCounter += 3;
			}
			break;
		}
		lineNumber += 1;
		Assembler.bufferedWriter.write(listFile.outputLine(index));
		Assembler.bufferedWriter.newLine();	
	}

	public static void putLabelInSymbolTable(String label){
		symbolTable.put(label, locationCounter);
	}

	public static void readLastLine() throws IOException{		
		int lastLine = Assembler.sourceFile.length - 1;		
		String [] line = Assembler.sourceFile[lastLine];	
		listFile = new ListFile();
		if(line.length == 2 && line[0].equals("END"))	{
			programLength = locationCounter - startingLocation;
			listFile.setIntermediateLineValue(lineNumber, line[0], line[1]);
		}else if(line[0].equals("END")){
			programLength = locationCounter;		
			listFile.mnemonic = line[0];
		}
		Assembler.bufferedWriter.write(listFile.outputLastLine(lastLine));
		Assembler.bufferedWriter.newLine();
		Assembler.bufferedWriter.write(Integer.valueOf(programLength).toString());
		Assembler.bufferedWriter.close();
	}

	private static void showErrorMessage(int line, String message) throws Exception{
		JOptionPane.showMessageDialog(null, "Error occured during Pass One at line number "
				+ Integer.toString(line) + ": " + message, "Error!",
				JOptionPane.ERROR_MESSAGE);
		Assembler.bufferedWriter.close();
		System.exit(1);
	}
	
	private static String testIfMnemonicIsFormatFour (String mnemonicString){
		originalMnemonic = mnemonicString;
		if (mnemonicString.startsWith("+")){
			formatFour = true;
			return mnemonicString.substring(1);
		}
		return mnemonicString;
	}
}